﻿using System;
using System.Text;
using System.Runtime.InteropServices;

namespace RobotGerchik
{
    static class MarshalUTF8
    {
        private static UTF8Encoding _utf8;

        //--------------------------------------------------------------------------------
        static MarshalUTF8()
        {
            _utf8 = new UTF8Encoding();
        }

        //--------------------------------------------------------------------------------
        public static IntPtr StringToHGlobalUTF8(String data)
        {
            Byte[] dataEncoded = _utf8.GetBytes(data + "\0");

            int size = Marshal.SizeOf(dataEncoded[0]) * dataEncoded.Length;

            IntPtr pData = Marshal.AllocHGlobal(size);

            Marshal.Copy(dataEncoded, 0, pData, dataEncoded.Length);

            return pData;
        }

        //--------------------------------------------------------------------------------
        public static String PtrToStringUTF8(IntPtr pData)
        {
            // this is just to get buffer length in bytes
            String errStr = Marshal.PtrToStringAnsi(pData);
            int length = errStr.Length;

            Byte[] data = new byte[length];
            Marshal.Copy(pData, data, 0, length);

            return _utf8.GetString(data);
        }
        //--------------------------------------------------------------------------------
    }
    public class TXmlConnector
    {
        const String EX_SETTING_CALLBACK = "Не смог установить функцию обратного вызова";

        private static volatile TXmlConnector _instance;
        private static object syncRoot = new Object();

        public delegate bool CallBack(IntPtr pData);
        public delegate bool CallBackEx(IntPtr pData, IntPtr userData);
        public CallBack myDelegate;
        public CallBackEx myDelegateEx;

        //public IList<string> DataList; // список строк с полученными от сервера данными
        public string debug_str;



        public TXmlConnector()
        {
            //DataList = new List<string>(1000);
            myDelegate = new CallBack(myCallBack);
            myDelegateEx = new CallBackEx(myCallBackEx);

            if (!SetCallback(myDelegate))
            {
                throw (new Exception(EX_SETTING_CALLBACK));
            }
            if (!SetCallbackEx(myDelegateEx, IntPtr.Zero))
            {
                throw (new Exception(EX_SETTING_CALLBACK));
            }
            _instance = this;
        }

        //--------------------------------------------------------------------------------
        public static TXmlConnector Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (syncRoot)
                    {
                        if (_instance == null)
                            _instance = new TXmlConnector();
                    }
                }

                return _instance;
            }
        }

        //--------------------------------------------------------------------------------
        public bool myCallBack(IntPtr pData)
        {
            String data = MarshalUTF8.PtrToStringUTF8(pData);
            FreeMemory(pData);

            RaiseNewDataEvent(data);
            //	DataList.Add(data);
            return true;
        }

        public bool myCallBackEx(IntPtr pData, IntPtr userData)
        {
            String data = MarshalUTF8.PtrToStringUTF8(pData);
            FreeMemory(pData);

            RaiseNewDataEvent(data);
            //	DataList.Add(data);
            return true;
        }

        //--------------------------------------------------------------------------------
        public class NewDataEventArgs : EventArgs
        {
            private String _data;
            public NewDataEventArgs(String data)
            {
                _data = data;
            }
            public String data
            {
                get
                {
                    return _data;
                }
            }
        }

        //--------------------------------------------------------------------------------
        public event EventHandler<NewDataEventArgs> NewData;
        public void RaiseNewDataEvent(String data)
        {
            EventHandler<NewDataEventArgs> handler = NewData;

            if (handler != null)
            {
                handler(new Object(), new NewDataEventArgs(data));
            }
        }


        //--------------------------------------------------------------------------------
        public String SendCommand(String command)
        {

            IntPtr pData = MarshalUTF8.StringToHGlobalUTF8(command);
            IntPtr pResult = SendCommand(pData);

            String result = MarshalUTF8.PtrToStringUTF8(pResult);



            Marshal.FreeHGlobal(pData);
            FreeMemory(pResult);

            return result;

        }


        public String ConnectorInitialize(String Path, Int16 LogLevel)
        {

            IntPtr pPath = MarshalUTF8.StringToHGlobalUTF8(Path);
            IntPtr pResult = Initialize(pPath, LogLevel);

            if (!pResult.Equals(IntPtr.Zero))
            {
                String result = MarshalUTF8.PtrToStringUTF8(pResult);
                Marshal.FreeHGlobal(pPath);
                FreeMemory(pResult);
                return result;
            }
            else
            {
                Marshal.FreeHGlobal(pPath);
                return "";
            }

        }


        public String ConnectorUnInitialize()
        {

            IntPtr pResult = UnInitialize();

            if (!pResult.Equals(IntPtr.Zero))
            {
                String result = MarshalUTF8.PtrToStringUTF8(pResult);
                FreeMemory(pResult);
                return result;
            }
            else
            {
                return "";
            }

        }


        //--------------------------------------------------------------------------------
        // файл библиотеки TXmlConnector.dll должен находиться в одной папке с программой
        //[DllImport("txcn.dll", CallingConvention = CallingConvention.StdCall)]
        //[DllImport("txmlconnector.dll", CallingConvention = CallingConvention.StdCall)]

        [DllImport("txmlconnector.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern bool SetCallback(CallBack pCallback);

        [DllImport("txmlconnector.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern bool SetCallbackEx(CallBackEx pCallback, IntPtr userData);

        [DllImport("txmlconnector.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern IntPtr SendCommand(IntPtr pData);

        [DllImport("txmlconnector.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern bool FreeMemory(IntPtr pData);

        [DllImport("TXmlConnector.dll", CallingConvention = CallingConvention.Winapi)]
        private static extern IntPtr Initialize(IntPtr pPath, Int32 logLevel);

        [DllImport("TXmlConnector.dll", CallingConvention = CallingConvention.Winapi)]
        private static extern IntPtr UnInitialize();

        [DllImport("TXmlConnector.dll", CallingConvention = CallingConvention.Winapi)]
        private static extern IntPtr SetLogLevel(Int32 logLevel);
        //--------------------------------------------------------------------------------
    }


    //================================================================================

}
